package xdu.lz.stage5_jucUtils.chapter5_lock.condition;

import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created at 2019/10/19 0019 下午 10:38
 *
 * 多个生产者消费者模型，利用存储队列
 */

public class ProduceComsumeCondition3 {

    private static ReentrantLock lock = new ReentrantLock();

    private static final Condition PRODUCER_CONDITION = lock.newCondition();

    private static final Condition CONSUMER_CONDITION = lock.newCondition();

    private static final int MAX_MESSAGE = 100;

    private static Queue<Integer> messageQueue = new LinkedList<>();

    private static AtomicInteger counter = new AtomicInteger(0);

    public static void produce(){
        try {
            lock.lock();
            while (messageQueue.size() >= MAX_MESSAGE){
                //等待
                PRODUCER_CONDITION.await();
            }
            //else produce
            System.out.println(Thread.currentThread().getName()+" produce "+counter.incrementAndGet());
            messageQueue.offer(counter.get());
            Thread.sleep(10);
            System.out.println("在阻塞等待的消费者数："+lock.getWaitQueueLength(CONSUMER_CONDITION));
            CONSUMER_CONDITION.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public static void consume(){
        try {
            lock.lock();
            while (messageQueue.isEmpty()){
                //等待
                CONSUMER_CONDITION.await();
            }
            //else produce
            System.out.println(Thread.currentThread().getName()+" consume "+ messageQueue.poll());
            System.out.println("在阻塞等待的生产者数："+lock.getWaitQueueLength(PRODUCER_CONDITION));
            PRODUCER_CONDITION.signalAll();
            Thread.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        for (int i = 0; i < 4; i++) {
            new Thread(()->{
                while (true) {
                    produce();
                }
            },"p"+i).start();
            new Thread(()->{
                while (true) {
                    consume();
                }
            },"c"+i).start();
        }
    }
}
